package 反射;
/*
通过反射创建对象，是通过第一章节中获取的Class实例（运行时类）来创建对象的。在java8及之前通过运行时类创建对象推荐调用Class实例的newInstance()方法。此方
法需要满足以下条件方可使用：
条件1：要求运行时类中必须提供一个空参的构造器
条件2：要求提供的空参的构造器的权限要足够。
    public void test1() throws InstantiationException, IllegalAccessException {
 
        Class clazz = Person.class;
 
        //创建Person类的实例
        Person per = (Person) clazz.newInstance();
 
        System.out.println(per);
    }
}
创建运行时类对象受限于两个条件，在java8之后，推荐使用Class实例获取构造器，通过构造器返回一个运行时类的实例对象。
public void test2() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
 
        Class clazz = Person.class;
 
        //1.通过Class的实例调用getDeclaredConstructor(Class ... args)，获取指定参数类型的构造器
        Constructor constructor = clazz.getDeclaredConstructor();
        
        //2.setAccessible(true)：确保此构造器是可以访问的
        constructor.setAccessible(true);
        
        //3.通过Constructor实例调用newInstance(Object ... objs),返回一个运行时类的实例。
        Person person = (Person) constructor.newInstance();
        
        System.out.println(person);
    }

Java通过反射机制实例化一个类的对象,步骤所用方法如下：
1. forName()   返回给定串名相应的Class对象。
2. newInstance()  创建类的新实例。
3. getConstructors()   返回当前Class对象表示的类的所有公有构造子对象数组。
4. getName()   返回Class对象表示的类型(类、接口、数组或基类型)的完整路径名字符串。

实例化一个类的对象*/
import java.lang.reflect.Constructor;
/*public class 反射实例化类 {
    public static void main(String[] args) throws Exception {
        Class<?> class1 = null;
        class1 = Class.forName("反射.User");
        // 第一种方法，实例化默认构造方法，调用set赋值

        //Constructor<?> con=class1.getDeclaredConstructor();
        //User user=(User)con.newInstance();
        User user = (User) class1.newInstance();//弃用，改用Constructor(见上两式)

        user.setAge(20);
        user.setName("Rollen");
        System.out.println(user);
        // 结果 User [age=20, name=Rollen]
        // 第二种方法 取得全部的构造函数 使用构造函数赋值
        Constructor<?> cons[] = class1.getConstructors();
        // 查看每个构造方法需要的参数
        for (int i = 0; i < cons.length; i++) {
            Class<?> clazzs[] = cons[i].getParameterTypes();
            System.out.print("cons[" + i + "] (");
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1)
                    System.out.print(clazzs[j].getName());
                else
                    System.out.print(clazzs[j].getName() + ",");
            }
            System.out.println(")");
        }
        // 结果
        // cons[0] (int,java.lang.String)
        // cons[1] (java.lang.String)
        // cons[2] ()
        user = (User) cons[1].newInstance("Rollen");
        System.out.println(user);
        // 结果 User [age=0, name=Rollen]
        user = (User) cons[0].newInstance(20, "Rollen");
        System.out.println(user);
        // 结果 User [age=20, name=Rollen]
    }
}
class User {
    private int age;
    private String name;
    public User() {
        super();
    }
    public User(String name) {
        super();
        this.name = name;
    }
    public User(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}*/

//反射：newInstance()的使用方式
//
//简介： 通过反射创建新的类示例，有两种方式，以下对两种调用方式给以比较说明：
// 
// -Class.newInstance() 只能够调用无参的构造函数，即默认的构造函数； 
// -Constructor.newInstance() 可以根据传入的参数，调用任意构造构造函数。
//
//Class.newInstance() 抛出所有由被调用构造函数抛出的异常。 
//
//Class.newInstance() 要求被调用的构造函数是可见的，也即必须是public类型的; 
//Constructor.newInstance() 在特定的情况下，可以调用私有的构造函数。 
//
//Class A（被调用的示例）： 
// 
class A {  
    private A() {  //使用 getDeclaredConstructor方法还可获得 private的构造方法。
        System.out.println("A's constructor is called.");  
    }  
  
    private A(int a, int b) {  
        System.out.println("a:" + a + " b:" + b);  
    }  
}  

//Class B（调用者）： 
 
//public class B {   
public class 反射实例化类 {   
    public static void main(String[] args) {   
    	反射实例化类 b=new 反射实例化类();   
        System.out.println("通过Class.NewInstance()调用私有构造函数:");   
        b.newInstanceByClassNewInstance();   
        System.out.println("通过Constructor.newInstance()调用私有构造函数:");   
        b.newInstanceByConstructorNewInstance();
    }   
    //通过Class.NewInstance()创建新的类示例 
    private void newInstanceByClassNewInstance(){   
        try {
      	  //当前包名为reflect，必须使用全路径  
            //A a=(A)Class.forName("反射.A").newInstance();   
            A a=A.class.newInstance();   
        } catch (Exception e) {   
        	System.out.println("通过Class.NewInstance()调用私有构造函数【失败】");   
        }  
    }  
      
    //通过Constructor.newInstance()创建新的类示例   
    private void newInstanceByConstructorNewInstance(){   
        try {//可以使用相对路径，同一个包中可以不用带包路径  
            Class<?> c=Class.forName("反射.A");   
            //以下调用无参的、私有构造函数*  
            Constructor<?> c0=A.class.getDeclaredConstructor(); //使用 getDeclaredConstructor方法还可获得 private的构造方法。
            c0.setAccessible(true);   
            A a0=(A)c0.newInstance();   
            //以下调用带参的、私有构造函数 
            Constructor<?> c1=c.getDeclaredConstructor(new Class[]{int.class,int.class});   
            c1.setAccessible(true);   
            A a1=(A)c1.newInstance(new Object[]{5,6});   
        } catch (Exception e) {   
            e.printStackTrace();   
        }   
    }   
}  


//输入结果如下： 
//通过Class.NewInstance()调用私有构造函数: 
//通过Class.NewInstance()调用私有构造函数【失败】 
//通过Constructor.newInstance()调用私有构造函数: 
//A's constructor is called. 
//a:5 b:6 
//
//说明方法newInstanceByClassNewInstance调用失败，而方法newInstanceByConstructorNewInstance则调用成功。 
//如果被调用的类的构造函数为默认的构造函数，采用Class.newInstance()则是比较好的选择，一句代码就OK；如果是老百姓调用被调用的类带参构造函数、私有构造函数， 
//就需要采用Constractor.newInstance()，两种情况视使用情况而定。不过Java Totorial中推荐采用Constractor.newInstance()。

